package main

import (
	"fmt"
	"sync"
)

/*
一、channel在类型上，可以分为两种：
1、双向channel：既能接收又能发送的channel(默认类型)
2、单向channel：只能发送或只能接收的channel，即单向channel可以为分为：
（1）只写channel
（2）只读channel
二、当我们在用channel进行参数传递的时候，希望对方单向使用，使得功能更加可控
三、声明单向通道的语法如下：
1、只写channel 发送通道（Send-only Channel）的声明： var ch chan<- int
2、只读channel 接收通道（Receive-only Channel）的声明：var ch <-chan int
<-表示单向的channel。如果箭头指向chan，就表示只写channel，可以往chan里边写入数据；
如果箭头远离chan，则表示为只读channel，可以从chan读数据。
注意，单向通道的类型可以基于普通的双向通道类型而来的。因此，你可以创建一个双向通道，然后使用类型转换将其转换为单向通道
*/

// 入参为单向只写channel
func sendWrite(sendData chan<- int) {
	defer Wg.Done()
	for i := 0; i < 10; i++ {
		sendData <- i * i //向单向管道写入发送数据
	}
	close(sendData) //写完之后关闭通道
}

// 入参为单向只读channel
func receiveRead(getData <-chan int) {
	defer Wg.Done()
	for v := range getData {
		fmt.Printf("getData: %d\n", v)
	}
}

var Wg sync.WaitGroup

func main() {
	//声明单向只写channel，只发送
	var writeMsg chan<- int
	writeMsg = make(chan int, 2)
	writeMsg <- 1 //写数据
	fmt.Println("writeMsg", writeMsg)

	//声明单向只读channel，只接收
	var readMsg <-chan int
	readMsg = make(chan int, 2)

	if readMsg == nil {
		mun := <-readMsg
		fmt.Println(mun)
	}
	//通过普通channel转我单向的channel
	var wrRe chan int        //声明可读可写的
	var Wr chan<- int = wrRe //write-only
	var Re <-chan int = wrRe // read-only
	fmt.Println(Wr, Re)

	// 单向channel在换出传参的时候的用法
	msg8 := make(chan int) //一般先定义普通的可读可写的

	Wg.Add(2)
	go sendWrite(msg8)   //可读可写的作为单向只写的入参
	go receiveRead(msg8) //可读可写的作为单向只读的入参
	Wg.Wait()
}
